package com.appshelves.model;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.List;

import com.appshelves.model.Model.Event;
import com.appshelves.model.saveable.Changeable;
import com.appshelves.model.saveable.ChangeableList;
import com.appshelves.model.saveable.SaveableList;
import com.appshelves.utils.Utils;

public class Shelf extends Changeable<Shelf> {
    private SaveableList<App> apps = new SaveableList<App>(App.class);
    private EventGenerator generator = new EventGenerator(EnumSet.range(Event.APPS_ADDED_TO_SHELF,
        Event.APP_MOVED_TO_TOP));

    Shelf(ChangeableList<Shelf> list, int numApps) {
        this(list);
        apps.ensureCapacity(numApps);
    }

    Shelf(ChangeableList<Shelf> list) {
        super(list);
    }

    SaveableList<App> getApps() {
        return apps;
    }

    void allocateSpace(int size) {
        apps.ensureCapacity(apps.size() + size);
    }

    void add(App app) {
        apps.add(app);
        markListChanged();
    }

    private void add(App app, int i) {
        apps.add(i, app);
        markListChanged();
    }

    void addToSortedPos(App app) {
        int pos = apps.size();
        while (pos != 0)
            if (apps.get(pos - 1).compareByLabel(app) < 0)
                break;
            else
                pos--;

        add(app, pos);
    }

    void add(List<App> apps) {
        this.apps.addAll(apps);
        markListChanged();
    }

    void remove(App app) {
        apps.remove(app);
        markListChanged();
    }

    void remove(List<App> toRemove) {
        apps.removeAll(toRemove);
        markListChanged();
    }

    void deleteApp(App app) {
        remove(app);
        app.onDelete();
    }

    void moveAppToTop(App app) {
        apps.remove(app);
        add(app, 0);
    }

    boolean isEmpty() {
        return apps.size() == 0;
    }

    int getAppPosition(App app) {
        return apps.indexOf(app);
    }

    void sortAlphabetically() {
        Collections.sort(apps, new Comparator<App>() {
            @Override
            public int compare(App lhs, App rhs) {
                return lhs.compareByLabel(rhs);
            }
        });

    }

    ///

    EventGenerator getGenerator() {
        return generator;
    }

    /// Serialization

    public Shelf() {
    }

    @Override
    protected void readFromStream(DataInputStream stream) throws IOException {
        apps.load(stream, this);
    }

    @Override
    protected void writeToStream(DataOutputStream stream) throws IOException {
        apps.saveToStream(stream);
    }

    /// debug

    protected void log() {
        Utils.log(this, "" + this);
        apps.log();
    }

}
